package com.AI.AIDemo.Demos;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * @author lenovo
 * {@code @Author:大力王}
 * {@code @Date:2025/10/13-13-9:46}
 * 开始了
 */
@Slf4j
@Data
public class RnnRandomForest {
    private int inputSize;
    private int hiddenLayers;
    private int outputSize;
    double sum;
    /**
     * 随机森林
     */
    private double[][] weights;
    private List<DecisionTree> forest;

    public RnnRandomForest(int inputSize, int hiddenLayers, int outputSize) {
        this.inputSize = inputSize;
        this.hiddenLayers = hiddenLayers;
        this.outputSize = outputSize;
        this.weights = initWeights(inputSize, hiddenLayers);
        this.forest = buildRandomForest(10);
    }

    /**
     * 权重初始化
     */
    private double[][] initWeights(int in,int  hidden) {
        Random random = new Random();
        // 确保权重矩阵的行数足够支持inputSize和hiddenLayers中的较大值
        int rows = Math.max(in, hidden);
        double[][] weights = new double[rows][in];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < in; j++) {
                weights[i][j] = random.nextGaussian() * 0.01;
            }
        }
        return weights;
    }

    /**
     * 构建随机森林
     * tree.setWeights(initWeights(inputSize, hiddenLayers));
     */
    private List<DecisionTree> buildRandomForest(int treeCount) {
        List<DecisionTree> trees = new ArrayList<>();
        for (int i = 0; i < treeCount; i++) {
            DecisionTree tree = new DecisionTree(inputSize, outputSize);
            trees.add(tree);
        }
        return trees;
    }

    /**
     * RNN隐藏层计算 (f函数: tanh激活)
     */
    private double[] f(double[] x, double[][] prevWeights) {
        double[] result  = new double[hiddenLayers];
        for (int i =0; i < hiddenLayers; i++){
            sum = 0;
            // 确保不会访问超出权重矩阵范围的行
            if (i < prevWeights.length) {
                for(int j = 0; j < Math.min(inputSize, Math.min(x.length, prevWeights[i].length)); j++){
                    sum += prevWeights[i][j] * x[j];
                }
            }
            result[i] = Math.tanh(sum + (i < x.length ? x[i] : 0));
        }
        return result;
    }

    /**
     * RNN特征选择函数 (t函数: sigmoid激活)
     */
    private double[] t(double[] x, double[][] prevWeights) {
        double[] result = new double[inputSize];
        for (int i = 0; i < inputSize; i++) {
            double sum = 0;
            // 确保不会访问超出权重矩阵范围的行
            if (i < prevWeights.length) {
                for (int j = 0; j < Math.min(inputSize, Math.min(x.length, prevWeights[i].length)); j++) {
                    sum += prevWeights[i][j] * x[j];
                }
            }
            // t函数: sigmoid激活
            result[i] = 1 / (1 + Math.exp(-sum - (i < x.length ? x[i] : 0)));
        }
        return result;
    }

    /**
     * 随机森林集成预测
     */
    private int forestPredict(double[] features) {
        Map<Integer, Integer> voteCount  = new HashMap<>(40);
        for (DecisionTree tree : forest) {
            int prediction = tree.predict(features);
            voteCount.put(prediction, voteCount.getOrDefault(prediction, 0) + 1);
        }
        // 查找投票数最多的动作
        Optional<Map.Entry<Integer, Integer>> maxEntry = voteCount.entrySet().stream()
                .max(Map.Entry.comparingByValue());
        
        if (maxEntry.isPresent()) {
            return maxEntry.get().getKey();
        } else {
            // 处理空的情况，可能抛出异常或返回默认值
            throw new IllegalStateException("没有可用的动作选择");
        }
    }

    /**
     * 特征融合与权重优化辅助函数
     */
    private double[] combineFeatures(double[] fOutput, double[] tOutput) {
        // 确保数组不为空
        if (fOutput == null || tOutput == null) {
            throw new IllegalArgumentException("输入数组不能为空");
        }
        
        double[] combined  = new double[fOutput.length + tOutput.length];
        System.arraycopy(fOutput, 0, combined, 0, fOutput.length);
        System.arraycopy(tOutput, 0, combined, fOutput.length, tOutput.length);
        return combined;
    }

    private double[][] optimizeWeights(double[][] weights, double[] tOutput) {
        double[][] newWeights  = Arrays.copyOf(weights, weights.length);
        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < weights[i].length; j++) {
                // 确保tOutput索引不越界
                if (i < tOutput.length) {
                    newWeights[i][j] *= (1 + tOutput[i] * 0.1);
                }
            }
        }
        return newWeights;
    }

    /**
     * 前向传播+反馈优化主流程
     */
    public int predict(double[] inputSequence) {
        // 确保输入序列不为空且长度合适
        if (inputSequence == null || inputSequence.length == 0) {
            throw new IllegalArgumentException("输入序列不能为空");
        }
        
        double[][] hiddenStates  = new double[hiddenLayers][inputSize];

        // 多层RNN处理 (d层隐藏层)
        for (int layer  = 0; layer  < hiddenLayers; layer++) {
            double[] fOutput = f(inputSequence, weights);
            double[] tOutput = t(inputSequence, weights);
            hiddenStates[layer] = combineFeatures(fOutput, tOutput);

            // 反馈路径: 使用中间结果优化下一层权重
            if (layer < hiddenLayers - 1) {
                weights  = optimizeWeights(weights, tOutput);
            }
        }

        // GO信号: 输出最终特征到随机森林
        double[] finalFeatures = hiddenStates[hiddenLayers - 1];
        return forestPredict(finalFeatures);
    }
}
